a tool for shared writing and social publishing
at update/thread-viewer 115 lines 3.6 kB view raw
1import { z } from "zod"; 2import { makeRoute } from "../lib"; 3import type { Env } from "./route"; 4import { AtUri } from "@atproto/syntax"; 5import { getFactsFromHomeLeaflets } from "./getFactsFromHomeLeaflets"; 6import { normalizeDocumentRecord } from "src/utils/normalizeRecords"; 7import { ids } from "lexicons/api/lexicons"; 8 9export type GetPublicationDataReturnType = Awaited< 10 ReturnType<(typeof get_publication_data)["handler"]> 11>; 12export const get_publication_data = makeRoute({ 13 route: "get_publication_data", 14 input: z.object({ 15 did: z.string(), 16 publication_name: z.string(), 17 }), 18 handler: async ( 19 { did, publication_name }, 20 { supabase }: Pick<Env, "supabase">, 21 ) => { 22 let pubLeafletUri; 23 let siteStandardUri; 24 if (/^(?!\.$|\.\.S)[A-Za-z0-9._:~-]{1,512}$/.test(publication_name)) { 25 pubLeafletUri = AtUri.make( 26 did, 27 ids.PubLeafletPublication, 28 publication_name, 29 ).toString(); 30 siteStandardUri = AtUri.make( 31 did, 32 ids.SiteStandardPublication, 33 publication_name, 34 ).toString(); 35 } 36 let { data: publication, error } = await supabase 37 .from("publications") 38 .select( 39 `*, 40 documents_in_publications(documents( 41 *, 42 comments_on_documents(count), 43 document_mentions_in_bsky(count) 44 )), 45 publication_subscriptions(*, identities(bsky_profiles(*))), 46 publication_domains(*), 47 leaflets_in_publications(*, 48 documents(*), 49 permission_tokens(*, 50 permission_token_rights(*), 51 custom_domain_routes!custom_domain_routes_edit_permission_token_fkey(*) 52 ) 53 )`, 54 ) 55 .or( 56 `name.eq."${publication_name}", uri.eq."${pubLeafletUri}", uri.eq."${siteStandardUri}"`, 57 ) 58 .eq("identity_did", did) 59 .order("uri", { ascending: false }) 60 .limit(1) 61 .single(); 62 63 let leaflet_data = await getFactsFromHomeLeaflets.handler( 64 { 65 tokens: 66 publication?.leaflets_in_publications.map( 67 (l) => l.permission_tokens?.root_entity!, 68 ) || [], 69 }, 70 { supabase }, 71 ); 72 73 // Pre-normalize documents from documents_in_publications 74 const documents = (publication?.documents_in_publications || []) 75 .map((dip) => { 76 if (!dip.documents) return null; 77 const normalized = normalizeDocumentRecord( 78 dip.documents.data, 79 dip.documents.uri, 80 ); 81 if (!normalized) return null; 82 return { 83 uri: dip.documents.uri, 84 record: normalized, 85 indexed_at: dip.documents.indexed_at, 86 sort_date: dip.documents.sort_date, 87 data: dip.documents.data, 88 commentsCount: dip.documents.comments_on_documents[0]?.count || 0, 89 mentionsCount: dip.documents.document_mentions_in_bsky[0]?.count || 0, 90 }; 91 }) 92 .filter((d): d is NonNullable<typeof d> => d !== null); 93 94 // Pre-filter drafts (leaflets without published documents, not archived) 95 const drafts = (publication?.leaflets_in_publications || []) 96 .filter((l) => !l.documents) 97 .filter((l) => !(l as { archived?: boolean }).archived) 98 .map((l) => ({ 99 leaflet: l.leaflet, 100 title: l.title, 101 permission_tokens: l.permission_tokens, 102 // Keep the full leaflet data for LeafletList compatibility 103 _raw: l, 104 })); 105 106 return { 107 result: { 108 publication, 109 documents, 110 drafts, 111 leaflet_data: leaflet_data.result, 112 }, 113 }; 114 }, 115});